﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Reflection;
using System.Collections.Generic;
using MetaCollection.Framework.Repository;

namespace MetaCollection.Framework.Provider
{

	/// <summary>
	/// Base Provider Implementation that all providers based on the MetaCollection ProviderType data model
	/// will inherit from.  Providers are what given implementations to the events in the request process.
	/// </summary>
	/// <remarks>
	/// When deriving from IProvider it is important that the class correctly implements the Initialize
	/// method.  This method should load the config in the <see cref="Model.ProviderType"/> passed to it.
	/// When loading the config an exception should be thrown if the configuration is invalid or missing.
	/// </remarks>
	public interface IProvider : IRequestSink
	{
		/// <summary>
		/// Unique Identifier of this provider.
		/// </summary>
		Guid Id { get; }

		/// <summary>
		/// Gets the name of this provider.
		/// </summary>
		/// <value>The name.</value>
		string Name { get; }

		/// <summary>
		/// Gets the friendly description of this provider.
		/// </summary>
		/// <value>The description.</value>
		string Description { get; }

		/// <summary>
		/// Initializes the provider specified in the ProviderType.
		/// </summary>
		/// <param name="providerConfig">The provider config.</param>
		/// <exception cref="System.ArgumentNullException">The name of the provider is null or one of the Repositories is null and it can not be created internally.</exception>
		/// <exception cref="System.ArgumentException">The name of the provider has a length of zero</exception>
		/// <exception cref="System.InvalidOperationException"> An attempt is made to call
		/// MetaCollection.Framework.Provider.IProvider.Initialize(MetaCollection.Framework.Model.IProviderType)
		/// on a provider after the provider has already been initialized</exception>
		void Initialize(MetaCollection.Framework.Configuration.ProviderReferenceElement providerConfig);

		/// <summary>
		/// Gets the Request Events that are supported by this provider.
		/// </summary>
		/// <value>RequestEventTypes supported by this provider</value>
		RequestEventTypes SupportedEvents { get; }
	}

	/// <summary>
	/// An extension that transforms a <see cref="Model.ProviderType"/> into a <see cref="IProvider"/>
	/// </summary>
	public static class ProviderTypeExtensions
	{
		/// <summary>
		/// Creates an instance of a provider from a <see cref="Model.ProviderType"/>
		/// </summary>
		/// <param name="providerConfig">The provider config.</param>
		/// <param name="itemRepository">The item repository (if set globally).</param>
		/// <param name="resourceRepository">The resource repository (if set globally).</param>
		/// <returns>
		/// An instance of the provider defined in the type record.
		/// </returns>
		public static IProvider CreateProvider(this Configuration.ProviderReferenceElement providerConfig)
		{
			if (providerConfig == null)
				throw new ArgumentNullException("providerConfig");

			if (String.IsNullOrEmpty(providerConfig.TypeName))
				throw new ArgumentNullException("providerConfig", "Type Name can not be null or empty in providerType.");

			Assembly asm;
			if (string.IsNullOrEmpty(providerConfig.AssemblyName))
				asm = Assembly.GetExecutingAssembly();
			else
				asm = Assembly.Load(providerConfig.AssemblyName);
			Type pType = asm.GetType(providerConfig.TypeName, true);

			IProvider result = Activator.CreateInstance(pType) as IProvider; // pType.TypeInitializer.Invoke(null) as IProvider;
			result.Initialize(providerConfig);
			return result;
		}
	}

}
